home *** CD-ROM | disk | FTP | other *** search
/ Plug-In Power Pack for Netscape Communicator / Plug-In Power Pack for Netscape Communicator.iso / plugins / dataviews / dvtools / examples / programs / textarray.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-08  |  37.7 KB  |  1,305 lines

  1. #ifndef    lint
  2. static char SccsId[]= "@(#)textarray.c    V1.30    3/13/95";
  3. #endif
  4. /* file name - textarray.c
  5. |===================================================================
  6. |
  7. |    module description/function:
  8. |    Example program for VUtextarray routines.
  9. |
  10. |    This program creates two text arrays,
  11. |    one for input and display, the other for output only.
  12. |    When the cursor is in the input text array,
  13. |    characters are echoed as they are typed.
  14. |    When a carriage-return or linefeed is hit, the entire line
  15. |    is echoed to the output only text array.
  16. |
  17. |
  18. |    The following characters are handled in a special way:
  19. |    ^R            refresh both text arrays
  20. |
  21. |
  22. |    The following chars have special meaning in the input area:
  23. |
  24. |    ^U            deletes the entire line
  25. |    ^W            deletes the current word
  26. |    ^L (FORM FEED)        clear both text arrays
  27. |    ^H (BKSP) or 0x7f (DEL)    back up one character
  28. |    ^J (LF) or ^M (CR)    move cursor to next line and echo input
  29. |                text array line to output text array
  30. |    ^I (TAB)        move cursor to next tab stop.
  31. |                (One tab stop every eight columns.)
  32. |
  33. |
  34. |    The following keys have special meaning in the input area:
  35. |
  36. |    LEFT mouse button (1)    Temporarily highlight one character
  37. |    MIDDLE mouse button (2)    Temporarily highlight string from
  38. |                highlighted character to cursor
  39. |
  40. |
  41. |    Quitting can be accomplished in any of the following ways:
  42. |    -- Pressing 'q' or 'Q' outside of the input text array.
  43. |    -- Pressing the RIGHT mouse button (3) anywhere in the window.
  44. |    -- Pressing the <ESC> key anywhere in the window.
  45. |
  46. |===================================================================
  47. |
  48. |  Possible enhancements:
  49. |    -- Teach the program to know about obscuring viewports.  Eg. let
  50. |    one text array (partially or entirely) obscure the other.
  51. |    And/or have obscuring objects maintain their integrity.
  52. |
  53. |===================================================================
  54. */
  55.  
  56. #include <windows.h>
  57. #include "std.h"
  58. #include "dvstd.h"
  59. #include "dvtools.h"
  60. #include "Tfundecl.h"
  61. #include "VOfundecl.h"
  62. #include "VUfundecl.h"
  63. #include "GRfundecl.h"
  64. #include "VUtextarray.h"
  65.  
  66. #define    DEFAULT_DEVICE_NAME    NULL    /* Use config var DVDEVICE */
  67. #define    DEFAULT_LAYOUT_FILE    "ta.lay"
  68. #define    DEFAULT_SEARCH_PATH    NULL    /* Use config var DVPATH */
  69.  
  70. /* Names of named objects in template */
  71. #define    INPUT    "input"                 /* place for input textarray */
  72. #define    OUTPUT    "output"                /* place for output textarray */
  73. #define    VISIBLE_AREA    "visible.area"  /* defines what portion of
  74.                                            view is to be visible */
  75.  
  76. #ifndef    __FILE__
  77. #define __FILE__    "textarray.c"
  78. #endif
  79.  
  80. /* Characters with which to do blank fill */
  81. #define    BLANK_CHAR_IN    '_'     /* on input */
  82. #define    BLANK_CHAR_OUT    ' '     /* on output */
  83.  
  84. LOCAL RECTANGLE                 /* coordinates of full screen */
  85.   vfull_screen =
  86. {
  87.   {0, 0},
  88.   {MAXCOORD, MAXCOORD}},        /* virtual coords */
  89.   sfull_screen =
  90. {
  91.   {0, 0},
  92.   {0, 0}};                      /* screen coordinates */
  93.  
  94. /* typedefs */
  95. typedef struct terminal
  96. {
  97.   TEXTARRAY ta;                 /* the text array */
  98.   TA_POSITION curpos;           /* position of the cursor */
  99.   DV_BOOL curdisp;              /* cursor displayed? */
  100. } TERMINAL;
  101.  
  102. /* macros */
  103. #define GET_CURSOR_POSITION( t, r, c )    ( (r) = (t)->curpos.row,\
  104.                       (c) = (t)->curpos.col,\
  105.                       &(t)->curpos )
  106. /*
  107. argv[1] - display device (default is DVDEVICE)
  108. argv[2] - layout for where to put objects (default is ta.lay)
  109. argv[3] - search path (default is DVPATH)
  110. */
  111.  
  112. /* Functions defined in textarray.c */
  113. LOCAL  DV_BOOL HandlePick V_P_((int key, int row_picked, int col_picked, 
  114.                            TERMINAL *in, TERMINAL *out));
  115. LOCAL  void Scroll V_P_((TERMINAL *t, int blank_char));
  116. LOCAL  DV_BOOL PresentCursor V_P_((TERMINAL *t, BOOLPARAM disp));
  117. LOCAL  DV_BOOL AdjustHighlight V_P_((TEXTARRAY ta, TA_POSITION *p1, 
  118.                                        TA_POSITION *p2, TA_POSITION *p));
  119. LOCAL  void MoveCursor V_P_((TERMINAL *t, int row, int col));
  120. LOCAL  void TaPosInc V_P_((TEXTARRAY ta, TA_POSITION *p));
  121. LOCAL  void TaPosDec V_P_((TEXTARRAY ta, TA_POSITION *p));
  122. LOCAL  void TaPosMidpt V_P_((TEXTARRAY ta, TA_POSITION *p1, TA_POSITION *p2, 
  123.                              TA_POSITION *mid));
  124. LOCAL  DV_BOOL Reverse V_P_((TEXTARRAY ta, TA_POSITION *p1, 
  125.                                TA_POSITION *p2));
  126. LOCAL  int TaPosCmp V_P_((TA_POSITION *p1, TA_POSITION *p2));
  127. LOCAL  void TaPosSort V_P_((TA_POSITION **p1, TA_POSITION **p2));
  128. LOCAL  char *Repl V_P_((char *buf, int from, int to));
  129. LOCAL  void Boxta V_P_((TEXTARRAY ta, int color));
  130. LOCAL  void PickRegion V_P_((char *msg, RECTANGLE *region));
  131. LOCAL  void Cross V_P_((DV_POINT *pt, int color));
  132. LOCAL  void GetScrBox V_P_((OBJECT obj, RECTANGLE *svp));
  133. LOCAL  void DrawBox V_P_((RECTANGLE *r, int color));
  134. LOCAL  void RectExpand V_P_((RECTANGLE *r, DV_COORD p));
  135. LOCAL  void cpybuf V_P_((char *to, char *from, int numchars));
  136. LOCAL  void Usage V_P_((char *ProgName));
  137. /***************** End Function Declarations *************/
  138.  
  139. int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 
  140.                      LPSTR lpCmdLine, int nCmdShow )
  141.  
  142. {
  143.   INT argc = 0;
  144.   CHAR **argv;
  145.  
  146. #define    ESC        0x1B        /* the Escape key */
  147. #define    REFRESH        0x12        /* ^R */
  148.   char *layout_file = DEFAULT_LAYOUT_FILE;
  149.   char *search_path = DEFAULT_SEARCH_PATH;
  150.   OBJECT screen;
  151.   OBJECT layout = (OBJECT) 0;
  152.   OBJECT
  153.     input = (OBJECT) 0,
  154.     output = (OBJECT) 0;
  155.   LOCAL TA_POSITION minsiz =
  156.   {2, 2};                    /* minimum size for each ta */
  157.   LOCAL DV_POINT             /* Points to fix input and output text arrays */
  158.     InPt =
  159.   {0, 0}, OutPt =
  160.   {0, 0};
  161.   LOCAL DV_POINT             /* Sizes of input and output text arrays */
  162.     InSz =
  163.   {0, 0}, OutSz =
  164.   {0, 0};
  165.   int poll_type = WAIT_PICK;
  166.   LOCAL TERMINAL
  167.     in,                      /* input area */
  168.     out;                     /* output area */
  169.   int                        /* local foreground & background color indices */
  170.     in_fore, in_back,
  171.     out_fore, out_back;
  172.   TA_RECT fullrect;
  173.   RECTANGLE in_svp;
  174.   RECTANGLE out_svp;
  175.   DRAWPORT dp = (DRAWPORT) 0;
  176.   VIEW view;
  177.   int rc = EXIT_OK;
  178.   char *prog_name = __FILE__;
  179.  
  180. /* Initialize search path */
  181.   if (argc > 3 && argv[3])
  182.     search_path = argv[3];
  183.   make_argv(&argc,&argv,GetCommandLine());
  184.   TInit (search_path, (char *) NULL);
  185.  
  186. /* Open display device */
  187.   if (argc > 1)
  188.     screen = TscOpenSet (argv[1], (char *) NULL,
  189.                          V_X_EXPOSURE_BLOCK, YES, V_END_OF_LIST);
  190.   else
  191.     screen = TscOpenSet ((char *) NULL, (char *) NULL,
  192.                          V_X_EXPOSURE_BLOCK, YES, V_END_OF_LIST);
  193.   if (!screen)
  194.     {
  195.       printf ("Must specify device on command line or");
  196.       printf (" in DataViews configuration file.\n");
  197.       TTerminate ();
  198.       exit (EXIT_ERR);
  199.     }
  200.  
  201. /* Get screen coordinates of full screen */
  202.   GRvcs_to_scs (&vfull_screen.ll, &sfull_screen.ll);
  203.   GRvcs_to_scs (&vfull_screen.ur, &sfull_screen.ur);
  204.  
  205. /* Get info from layout, if available */
  206.   if (argc > 2 && argv[2])
  207.     layout_file = argv[2];
  208.   if (layout_file && 0 != strcmp (layout_file, "0") &&
  209.       (layout = TviGetDrawing (view = TviLoad (layout_file))))
  210.     {
  211.       /* Get location of input text array */
  212.       input = TdrGetNamedObject (layout, INPUT);
  213.       if (input)
  214.     /* set parameters to VUtaCreate for input textarray */
  215.         {                       
  216.           GetScrBox (input, &in_svp);
  217.           cpybuf ((char *) & InPt, (char *) & in_svp.ll, sizeof (in_svp.ll));
  218.           InSz.x = in_svp.ur.x - in_svp.ll.x + 1;
  219.           InSz.y = in_svp.ur.y - in_svp.ll.y + 1;
  220.           VOdrObDelete (layout, VOobReference (input));
  221.         }
  222.  
  223.       /* Get location of output text array */
  224.       output = TdrGetNamedObject (layout, OUTPUT);
  225.       if (output)
  226.     /* set parameters to VUtaCreate for output textarray */
  227.         {                       
  228.           GetScrBox (output, &out_svp);
  229.           cpybuf ((char *) & OutPt,
  230.                   (char *) & out_svp.ll, sizeof (out_svp.ll));
  231.           OutSz.x = out_svp.ur.x - out_svp.ll.x + 1;
  232.           OutSz.y = out_svp.ur.y - out_svp.ll.y + 1;
  233.           VOdrObDelete (layout, VOobReference (output));
  234.         }
  235.     }
  236.  
  237. /* Initialize info that was unavailable from layout */
  238.   if (!input || !output)
  239.     {
  240.       TscErase (screen);
  241.       if (!input)
  242.         {
  243.           PickRegion ("Pick two points for input text array.",
  244.                              &in_svp);
  245.           cpybuf ((char *) & InPt, (char *) & in_svp.ll, sizeof (InPt));
  246.           InSz.x = in_svp.ur.x - in_svp.ll.x + 1;
  247.           InSz.y = in_svp.ur.y - in_svp.ll.y + 1;
  248.         }
  249.       if (!output)
  250.         {
  251.           PickRegion ("Pick two points for output text array.",
  252.                              &out_svp);
  253.           cpybuf ((char *) & OutPt, (char *) & out_svp.ll, sizeof (OutPt));
  254.           OutSz.x = out_svp.ur.x - out_svp.ll.x + 1;
  255.           OutSz.y = out_svp.ur.y - out_svp.ll.y + 1;
  256.         }
  257.     }
  258.  
  259. /* Create the textarrays */
  260.   in.ta = VUtaCreate ((ULONG) (V_OP_LL | V_RSLVE_GREATER | V_SLOP_SHRINK),
  261.                       &InPt, &InSz, &minsiz,
  262.                       DEF_TEXT_SIZE, (int *) NULL);
  263.   out.ta = VUtaCreate ((ULONG) (V_OP_LL | V_RSLVE_GREATER | V_SLOP_SHRINK),
  264.                        &OutPt, &OutSz, &minsiz,
  265.                        DEF_TEXT_SIZE, (int *) NULL);
  266.   if (!in.ta || !out.ta)
  267.     {
  268.       fprintf (
  269.                        stderr, "%s: Could not create %s\n", prog_name,
  270.                        in.ta ? "output textarray" :
  271.           (out.ta ? "input textarray" : "input or output textarray"));
  272.       rc = EXIT_ERR;
  273.       goto err_exit;
  274.     }
  275.   else
  276.     {
  277.       in_back = VUtaGetColor (in.ta, 0);
  278.       in_fore = VUtaGetColor (in.ta, 1);
  279.       out_back = VUtaGetColor (out.ta, 0);
  280.       out_fore = VUtaGetColor (out.ta, 1);
  281.     }
  282. /* Get real bounding box of text arrays */
  283.   VUtaBox (in.ta, &in_svp);
  284.   VUtaBox (out.ta, &out_svp);
  285.  
  286. /* Erase the screen before doing any graphics */
  287.   TscErase (screen);
  288.  
  289. /* Draw decoration, if any */
  290.   if (view && layout)
  291.     {
  292.       LOCAL RECTANGLE wvp_drawing =
  293.       {
  294.         {-16383, -16383},
  295.         {16383, 16383}};
  296.       RECTANGLE svp_delta;
  297.       OBJECT visible_area;
  298.  
  299.       /* Get bounding box of area to display */
  300.       visible_area = TdrGetNamedObject (layout, VISIBLE_AREA);
  301.       if (visible_area)
  302.         VOobBox (visible_area, &wvp_drawing, &svp_delta);
  303.       else
  304.         VOobBox (layout, &wvp_drawing, &svp_delta);
  305.  
  306.       /* Try to make sense of the svp_delta */
  307.       GRscs_to_vcs (&svp_delta.ll, &svp_delta.ll);
  308.       GRscs_to_vcs (&svp_delta.ur, &svp_delta.ur);
  309.       wvp_drawing.ll.x += svp_delta.ll.x;
  310.       wvp_drawing.ll.y += svp_delta.ll.y;
  311.       wvp_drawing.ur.x += svp_delta.ur.x;
  312.       wvp_drawing.ur.y += svp_delta.ur.y;
  313.  
  314.       /* Create drawport */
  315.       dp = TdpCreateStretch (screen, view,
  316.                              (RECTANGLE *) NULL, &wvp_drawing);
  317.       TdpDraw (dp);
  318.     }
  319.  
  320. /* Draw rectangles around the text arrays */
  321.   Boxta (in.ta, in_fore);
  322.   Boxta (out.ta, out_fore);
  323.  
  324. /* fill text arrays with underscores and set cursor positions */
  325.   V_TRSET (&fullrect, 0, 0,
  326.            VUtaGetHeight (in.ta) - 1,
  327.            VUtaGetWidth (in.ta) - 1);
  328.   VUtaFillRect (in.ta, &fullrect, BLANK_CHAR_IN, V_TA_NORMAL);
  329.   V_TPSET (&in.curpos, 0, 0);
  330.   in.curdisp = NO;
  331.   V_TRSET (&fullrect, 0, 0,
  332.            VUtaGetHeight (out.ta) - 1,
  333.            VUtaGetWidth (out.ta) - 1);
  334.   VUtaFillRect (out.ta, &fullrect, BLANK_CHAR_OUT, V_TA_NORMAL);
  335.   V_TPSET (&out.curpos, 0, 0);
  336.   out.curdisp = NO;
  337.  
  338. /* Show cursor on input, but not on output */
  339.   PresentCursor (&in, (DV_BOOL) YES);
  340.   PresentCursor (&out, (DV_BOOL) NO);
  341.   VUtaDraw (in.ta, (RECTANGLE **) NULL);
  342.   VUtaDraw (out.ta, (RECTANGLE **) NULL);
  343.   GRflush ();
  344.  
  345. /* Get input from in.ta and output it to out.ta */
  346.   FOREVER
  347.   {
  348.     DV_BOOL curdisp_in;            /* cursor displayed in input text array? */
  349.     DV_BOOL curdisp_out;           /* cursor displayed in output text array? */
  350.     OBJECT loc;
  351.     int key;
  352.     DV_POINT p;
  353.     TA_POSITION tp;             /* general purpose character position */
  354.     DV_BOOL err = DV_SUCCESS;   /* possible error from called routines */
  355.  
  356.  
  357.     loc = TloPoll (poll_type);
  358.     key = VOloKey (loc);
  359.     cpybuf ((char *) & p, (char *) VOloScpGet (loc), sizeof (p));
  360.     if ('\003' == key || ESC == key)    /* quit */
  361.       break;
  362.     else if (REFRESH == key)
  363.       {
  364.         /* Get new upper right portion of screen */
  365.         GRreset ();
  366.         GRvcs_to_scs (&vfull_screen.ur, &p);
  367.         if (p.x != sfull_screen.ur.x || p.y != sfull_screen.ur.y)
  368.           {
  369.             TEXTARRAY           /* the (now) old text arrays */
  370.               old_in = in.ta,
  371.               old_out = out.ta;
  372.             /* height and width of (now) old and new text arrays */
  373.             int old_height, new_height;
  374.             int old_width, new_width;
  375.             TA_RECT crect;      /* char rect used for rectangular fills */
  376.  
  377.             /* Set new screen dimensions */
  378.             sfull_screen.ur.x = p.x;
  379.             sfull_screen.ur.y = p.y;
  380.  
  381.             /* Recalculate drawports */
  382.             err &= TscReset (screen);
  383.             /* On some window systems we may not need to redraw, as resizing
  384.              | also generates an expose event. Others may never generate
  385.              | expose events. On still others, enlarging
  386.              | a window generates an expose, but shrinking doesn't.
  387.              | To be as general as possible, here we will always
  388.              | redraw the screen even though some users will see
  389.              | two redraws.
  390.              */
  391.             TscRedraw (screen, (RECTANGLE *) NULL);
  392.  
  393.             /* Recalculate boundaries of text arrays */
  394.             if (input)
  395.               {
  396.                 GetScrBox (input, &in_svp);
  397.                 cpybuf ((char *) & InPt,
  398.                         (char *) & in_svp.ll, sizeof (in_svp.ll));
  399.                 InSz.x = in_svp.ur.x - in_svp.ll.x + 1;
  400.                 InSz.y = in_svp.ur.y - in_svp.ll.y + 1;
  401.               }
  402.  
  403.             if (output)
  404.               {
  405.                 GetScrBox (output, &out_svp);
  406.                 cpybuf ((char *) & OutPt,
  407.                         (char *) & out_svp.ll, sizeof (out_svp.ll));
  408.                 OutSz.x = out_svp.ur.x - out_svp.ll.x + 1;
  409.                 OutSz.y = out_svp.ur.y - out_svp.ll.y + 1;
  410.               }
  411.  
  412.             /* Create the new textarrays (resize with new window size) */
  413.             in.ta =
  414.               VUtaCreate ((ULONG) (V_OP_LL | V_RSLVE_GREATER | V_SLOP_SHRINK),
  415.                           &InPt, &InSz, &minsiz,
  416.                           DEF_TEXT_SIZE, (int *) NULL);
  417.             out.ta =
  418.               VUtaCreate ((ULONG) (V_OP_LL | V_RSLVE_GREATER | V_SLOP_SHRINK),
  419.                           &OutPt, &OutSz, &minsiz,
  420.                           DEF_TEXT_SIZE, (int *) NULL);
  421.  
  422.             /* Copy the contents of the old text arrays into the new ones */
  423.             err &= VUtaCopyRect (in.ta, (TA_RECT *) NULL,
  424.                                  old_in, (TA_RECT *) NULL);
  425.             err &= VUtaCopyRect (out.ta, (TA_RECT *) NULL,
  426.                                  old_out, (TA_RECT *) NULL);
  427.  
  428.             /* If either text array got bigger,
  429.             |  fill out the enlarged parts with
  430.             |  the appropriate blank characters. */
  431.             old_height = VUtaGetHeight (old_in);
  432.             new_height = VUtaGetHeight (in.ta);
  433.             old_width = VUtaGetWidth (old_in);
  434.             new_width = VUtaGetWidth (in.ta);
  435.             if (new_width > old_width)
  436.               err &= VUtaFillRect (in.ta,
  437.                                    V_TRSET (&crect, 0, old_width,
  438.                                        old_height - 1, new_width - 1),
  439.                                    BLANK_CHAR_IN, V_TA_NORMAL);
  440.             if (new_height > old_height)
  441.               err &= VUtaFillRect (in.ta,
  442.                                    V_TRSET (&crect, old_height, 0,
  443.                                        new_height - 1, new_width - 1),
  444.                                    BLANK_CHAR_IN, V_TA_NORMAL);
  445.             old_height = VUtaGetHeight (old_out);
  446.             new_height = VUtaGetHeight (out.ta);
  447.             old_width = VUtaGetWidth (old_out);
  448.             new_width = VUtaGetWidth (out.ta);
  449.             if (new_width > old_width)
  450.               err &= VUtaFillRect (out.ta,
  451.                                    V_TRSET (&crect, 0, old_width,
  452.                                        old_height - 1, new_width - 1),
  453.                                    BLANK_CHAR_OUT, V_TA_NORMAL);
  454.             if (new_height > old_height)
  455.               err &= VUtaFillRect (out.ta,
  456.                                    V_TRSET (&crect, old_height, 0,
  457.                                        new_height - 1, new_width - 1),
  458.                                    BLANK_CHAR_OUT, V_TA_NORMAL);
  459.  
  460.             /* Adjust cursor positions, if necessary */
  461.             if (in.curpos.row >= new_height || in.curpos.col >= new_width)
  462.               {
  463.                 in.curpos.row = S_MIN (in.curpos.row, new_height - 1);
  464.                 in.curpos.col = S_MIN (in.curpos.col, new_width - 1);
  465.                 err &= VUtaSwapColor (in.ta, &in.curpos, 1);
  466.               }
  467.             if (out.curpos.row >= new_height || out.curpos.col >= new_width)
  468.               {
  469.                 out.curpos.row = S_MIN (out.curpos.row, new_height - 1);
  470.                 out.curpos.col = S_MIN (out.curpos.col, new_width - 1);
  471.                 err &= VUtaSwapColor (out.ta, &out.curpos, 1);
  472.               }
  473.  
  474.             /* Destroy old text arrays */
  475.             err &= VUtaDestroy (old_in);
  476.             err &= VUtaDestroy (old_out);
  477.  
  478.             /* Get real bounding box of text arrays */
  479.             VUtaBox (in.ta, &in_svp);
  480.             VUtaBox (out.ta, &out_svp);
  481.           }
  482.  
  483.         /* Draw decoration, if any */
  484.         if (dp)
  485.           err &= TdpRedraw (dp, (RECTANGLE *) NULL, YES);
  486.         else
  487.           err &= TscErase (screen);
  488.  
  489.         /* Draw rectangles around the text arrays */
  490.         Boxta (in.ta, in_fore);
  491.         Boxta (out.ta, out_fore);
  492.  
  493.         /* refresh input objects */
  494.         err &= VUtaRedraw (in.ta, (RECTANGLE **) NULL);
  495.         err &= VUtaRedraw (out.ta, (RECTANGLE **) NULL);
  496.  
  497.         err &= GRflush ();
  498.         if (DV_FAILURE == err)
  499.           {
  500.             rc = EXIT_ERR;
  501.             break;
  502.           }
  503.       }
  504.  
  505.     else if (VUtaScreenToChar (in.ta, &p, &tp))
  506.       {
  507.         /* Turn cursors off */
  508.         curdisp_in = PresentCursor (&in, (DV_BOOL) NO);
  509.         curdisp_out = PresentCursor (&out, (DV_BOOL) NO);
  510.  
  511.         /* Handle the user pick */
  512.         if (!HandlePick (key, tp.row, tp.col, &in, &out))
  513.           {
  514.             rc = EXIT_ERR;
  515.             break;
  516.           }
  517.  
  518.         /* Turn the cursors back on */
  519.         PresentCursor (&in, curdisp_in);
  520.         PresentCursor (&out, curdisp_out);
  521.  
  522.         /* Draw text arrays to the screen */
  523.         err &= VUtaDraw (in.ta, (RECTANGLE **) NULL);
  524.         err &= VUtaDraw (out.ta, (RECTANGLE **) NULL);
  525.         err &= GRflush ();
  526.       }
  527.     else if ('q' == key || 'Q' == key)  /* quit */
  528.       break;
  529.   }
  530.  
  531. /* Clean up and exit */
  532.   if (input)
  533.     VOobDereference (input);
  534.   if (output)
  535.     VOobDereference (output);
  536.   if (dp)
  537.     TdpDestroy (dp);
  538.   GRcolor (in_back);
  539.   GRf_rectangle (&in_svp.ll, &in_svp.ur);
  540.   GRcolor (out_back);
  541.   GRf_rectangle (&out_svp.ll, &out_svp.ur);
  542.  
  543. err_exit:
  544.   if (in.ta)
  545.     VUtaDestroy (in.ta);
  546.   if (out.ta)
  547.     VUtaDestroy (out.ta);
  548.   if (view)
  549.     TviDestroy (view);
  550.   TscErase (screen);
  551.   TscClose (screen);
  552.   TTerminate ();
  553.   return rc;
  554. }
  555.  
  556. /* HandlePick()
  557. |
  558. |  Handle the character that was typed
  559. |  in the region of the input text array.
  560. */
  561. LOCAL DV_BOOL 
  562. HandlePick (key, row_picked, col_picked, in, out)
  563.      int key;
  564.      int row_picked;
  565.      int col_picked;
  566.      TERMINAL *in;
  567.      TERMINAL *out;
  568. {
  569. #define    DELETE_LINE    0x15    /* ^U */
  570. #define    DELETE_WORD    0x17    /* ^W */
  571. #define    DELETE_CHAR    0x7F    /* DEL key */
  572. #define    CLEAR_TAS    '\f'    /* ^L -- clear both text arrays */
  573. #define    TAB_STOP    8
  574.   LOCAL DV_BOOL wraparound = YES;
  575.   LOCAL char us = BLANK_CHAR_IN;
  576.   LOCAL char *buf = NULL;
  577.   DV_BOOL rc = DV_SUCCESS;      /* return code */
  578.   int
  579.     row,
  580.     col,
  581.     in_height,
  582.     in_width,
  583.     out_row,
  584.     out_col,
  585.     out_height,
  586.     out_width,
  587.     width;
  588.   TA_RECT trect;
  589.   static TA_POSITION
  590.     p1 =
  591.   {-1, -1}, p2 =
  592.   {-1, -1};
  593.   TA_POSITION tp;               /* general purpose character position */
  594.   char *bptr;                   /* ptr for backing up to beginning of word */
  595.   char *dptr;                   /* ptr for deleting chars within a word */
  596.  
  597.  
  598. /* Get current position of cursor */
  599.   GET_CURSOR_POSITION (in, row, col);
  600.  
  601. /* Get height and width of text arrays */
  602.   in_height = VUtaGetHeight (in->ta);
  603.   in_width = VUtaGetWidth (in->ta);
  604.   out_height = VUtaGetHeight (out->ta);
  605.   out_width = VUtaGetWidth (out->ta);
  606.  
  607. /* Initialize buffer */
  608.   if (!buf)
  609.     buf = S_ALLOC ((unsigned)in_width + 1);
  610.  
  611. /* If not highlighting, undo effects of existing highlighting */
  612.   if ('\002' != key)
  613.     {
  614.       if (p1.row >= 0 && p1.col >= 0)
  615.         if (p2.row >= 0 && p2.col >= 0)
  616.           rc &= Reverse (in->ta, &p1, &p2);
  617.         else
  618.           rc &= Reverse (in->ta, &p1, &p1);
  619.       p1.row = p1.col = p2.row = p2.col = -1;
  620.     }
  621.  
  622. /* Deal with the key in its own special way */
  623.   switch (key)
  624.     {
  625.     case '\000':               /* Ignore weird keys like <SHIFT> and <CTL> */
  626.       break;
  627.  
  628.     case '\001':               /* left mouse button: highlight one character */
  629.       p1.row = p2.row = row_picked;
  630.       p1.col = p2.col = col_picked;
  631.       rc &= Reverse (in->ta, &p1, &p1);
  632.       break;
  633.  
  634.     case '\002':               /* middle mouse button: highlight region */
  635.       if (p1.row >= 0 && p1.col >= 0)
  636.         {
  637.           TA_POSITION ptmp;
  638.  
  639.           if (p2.row < 0 || p2.col < 0)
  640.             {
  641.               p2.row = p1.row;
  642.               p2.col = p1.col;
  643.             }
  644.           ptmp.row = row_picked;
  645.           ptmp.col = col_picked;
  646.           rc &= AdjustHighlight (in->ta, &p1, &p2, &ptmp);
  647.         }
  648.       break;
  649.  
  650.     case DELETE_LINE:          /* delete entire line */
  651.       MoveCursor (in, row, 0);
  652.       rc &= VUtaPutChar (in->ta, BLANK_CHAR_IN, V_TA_NORMAL,
  653.                          V_TPSET (&tp, row, 0), in_width);
  654.       break;
  655.  
  656.     case DELETE_WORD:          /* delete previous word */
  657.       /* Get string up to cursor position */
  658.       if (strlen (VUtaGetString (in->ta, buf, (TA_PACKED_COLOR *) NULL,
  659.                                    V_TPSET (&tp, row, 0), col)) <= 0)
  660.         break;
  661.  
  662.       /* eliminate trailing blanks */
  663.       for (bptr = buf + strlen (buf); bptr > buf; bptr--)
  664.         if (*(bptr - 1) != BLANK_CHAR_IN &&
  665.             *(bptr - 1) != BLANK_CHAR_OUT)
  666.           break;
  667.  
  668.       /* eliminate word itself */
  669.       while (bptr > buf)
  670.         if (BLANK_CHAR_IN == *(bptr - 1) ||
  671.             BLANK_CHAR_OUT == *(bptr - 1))
  672.           break;
  673.         else
  674.           bptr--;
  675.  
  676.       /* delete the word in the buffer */
  677.       for (dptr = bptr; *dptr; dptr++)
  678.         *dptr = BLANK_CHAR_IN;
  679.  
  680.       /* write altered part of the buffer back to the text array */
  681.       rc &= VUtaPutString (in->ta, bptr, V_TA_NORMAL,
  682.                            V_TPSET (&tp, row, bptr - buf), -1);
  683.  
  684.       /* Move cursor back */
  685.       in->curpos.col -= strlen (bptr);
  686.       break;
  687.  
  688.     case '\t':                 /* tab: write spaces to next tab stop */
  689.       if (col < in_width - 1)
  690.         do
  691.           rc &= VUtaPutChar (in->ta, BLANK_CHAR_IN, V_TA_NORMAL,
  692.                              V_TPSET (&tp, row, col++), 1);
  693.         while (col < in_width - 1 && col % TAB_STOP != 0);
  694.       if (col >= in_width)
  695.         col--;
  696.       MoveCursor (in, row, col);
  697.       break;
  698.  
  699.     case '\b':                 /* backspace: back up one character */
  700.     case DELETE_CHAR:          /* treat the delete key same as the backspace */
  701.       if (col > 0)
  702.         {
  703.           rc &= VUtaPutChar (in->ta, us, V_TA_NORMAL,
  704.                              V_TPSET (&tp, row, col - 1), 1);
  705.           MoveCursor (in, row, col - 1);
  706.         }
  707.       break;
  708.  
  709.     case CLEAR_TAS:            /* form feed: clear both textarrays */
  710.       V_TRSET (&trect, 0, 0, in_height - 1, in_width - 1);
  711.       rc &= VUtaFillRect (in->ta, &trect,
  712.                           BLANK_CHAR_IN, V_TA_NORMAL);
  713.       MoveCursor (in, 0, 0);
  714.       V_TRSET (&trect, 0, 0, out_height - 1, out_width - 1);
  715.       rc &= VUtaFillRect (out->ta, &trect,
  716.                           BLANK_CHAR_OUT, V_TA_NORMAL);
  717.       MoveCursor (out, 0, 0);
  718.       break;
  719.  
  720.     default:                   /* simply display char */
  721.       rc &= VUtaPutChar (in->ta, key, V_TA_NORMAL,
  722.                          V_TPSET (&tp, row, col), 1);
  723.       if (++col < in_width || !wraparound)
  724.         {
  725.           MoveCursor (in, row, col);
  726.           break;
  727.         }
  728.       /* else scroll */
  729.  
  730.     case '\r':                 /* Treat CR the same as newline */
  731.     case '\n':                 /* new line: flush line to output ta */
  732.       /* flush to out->ta */
  733.       width = S_MIN (in_width, out_width);
  734.       if (strlen (VUtaGetString (in->ta, buf, (TA_PACKED_COLOR *) NULL,
  735.                                    V_TPSET (&tp, row, 0), width)) > 0)
  736.         {
  737.           LOCAL DV_BOOL first_time_last_line = YES;
  738.  
  739.           GET_CURSOR_POSITION (out, out_row, out_col);
  740.           if (out_row >= out_height - 1)
  741.             if (first_time_last_line)
  742.               first_time_last_line = NO;
  743.             else
  744.               Scroll (out, BLANK_CHAR_OUT);
  745.           rc &= VUtaPutString (out->ta,
  746.                                Repl (buf, BLANK_CHAR_IN,
  747.                                      BLANK_CHAR_OUT),
  748.                                V_TA_NORMAL,
  749.                                V_TPSET (&tp, out_row, out_col),
  750.                                out_width);
  751.           if (out_row < out_height - 1)
  752.             MoveCursor (out, ++out_row, 0);
  753.         }
  754.       if (row >= in_height - 1)
  755.         Scroll (in, BLANK_CHAR_IN);
  756.       else
  757.         MoveCursor (in, ++row, 0);
  758.       break;
  759.     }
  760.  
  761.   return rc;
  762. }
  763.  
  764. /* Scroll()
  765. |
  766. |  Scroll the given textarray up by one row.
  767. |  Assumes the cursor is not currently displayed.
  768. */
  769. LOCAL void 
  770. Scroll (t, blank_char)
  771.      TERMINAL *t;
  772.      int blank_char;
  773. {
  774.   int height, width;
  775.   TA_RECT trect;
  776.  
  777. /* Get height and width of text arrays */
  778.   height = VUtaGetHeight (t->ta);
  779.   width = VUtaGetWidth (t->ta);
  780.  
  781.   V_TRSET (&trect, 1, 0, height - 1, width - 1);
  782.   VUtaMoveRect (t->ta, &trect, -1 /* -1 down == 1 up */ , 0);
  783.   V_TRSET (&trect, height - 1, 0, height - 1, width - 1);
  784.   VUtaFillRect (t->ta, &trect, blank_char, V_TA_NORMAL);
  785.   MoveCursor (t, height - 1, 0);
  786. }
  787.  
  788. /* PresentCursor()
  789. |
  790. |  Change visibility of the cursor.
  791. |  Return whether or not cursor was previously displayed.
  792. */
  793. LOCAL DV_BOOL 
  794. PresentCursor (t, disp)
  795.      TERMINAL *t;
  796.      BOOLPARAM disp;
  797. {
  798.   if (disp == t->curdisp)
  799.     return disp;
  800.   else
  801.     {
  802.       /* Change display of cursor in text array */
  803.       VUtaSwapColor (t->ta, &t->curpos, 1);
  804.       t->curdisp = disp;
  805.       return !disp;
  806.     }
  807. }
  808.  
  809. /* AdjustHighlight()
  810. |
  811. |  Adjust the highlighted text.  If the pick is outsied the
  812. |  highlighted region, extend the highlighted region.  If it
  813. |  is inside the region, shrink the region.
  814. |
  815. |  Note that p1, p2, and p must be point to _different_ locations.
  816. */
  817.  
  818. LOCAL DV_BOOL 
  819. AdjustHighlight (ta, p1, p2, p)
  820.      TEXTARRAY ta;
  821.      TA_POSITION *p1;
  822.      TA_POSITION *p2;
  823.      TA_POSITION *p;
  824. {
  825.   DV_BOOL rc = DV_SUCCESS;            /* return code */
  826.  
  827. /* Insure p1 is before p2 */
  828.   TaPosSort (&p1, &p2);
  829.  
  830. /* Adjust highlighting */
  831.   if (TaPosCmp (p, p1) < 0)           /* Expand to left */
  832.     {
  833.       TaPosDec (ta, p1);
  834.       rc &= Reverse (ta, p, p1);
  835.       p1->row = p->row;
  836.       p1->col = p->col;
  837.     }
  838.   else if (TaPosCmp (p, p2) > 0)      /* or expand to right */
  839.     {
  840.       TaPosInc (ta, p2);
  841.       rc &= Reverse (ta, p2, p);
  842.       p2->row = p->row;
  843.       p2->col = p->col;
  844.     }
  845.  
  846. /* or Shrink highlighted region */
  847.   else
  848.     {
  849.       TA_POSITION pmid;
  850.  
  851.       TaPosMidpt (ta, p1, p2, &pmid);
  852.       if (TaPosCmp (p, &pmid) >= 0)   /* shrink from right */
  853.         {
  854.           TaPosInc (ta, p);
  855.           if (TaPosCmp (p, p2) <= 0)
  856.             {
  857.               rc &= Reverse (ta, p2, p);
  858.               p2->row = p->row;
  859.               p2->col = p->col;
  860.               TaPosDec (ta, p2);
  861.             }
  862.         }
  863.       else
  864.         /* shrink from left */
  865.         {
  866.           TaPosDec (ta, p);
  867.           if (TaPosCmp (p1, p) <= 0)
  868.             {
  869.               rc &= Reverse (ta, p1, p);
  870.               p1->row = p->row;
  871.               p1->col = p->col;
  872.               TaPosInc (ta, p1);
  873.             }
  874.         }
  875.     }
  876.  
  877.   return rc;
  878. }
  879.  
  880. /* MoveCursor()
  881. |
  882. |  Change the position of the cursor.
  883. */
  884. LOCAL void 
  885. MoveCursor (t, row, col)
  886.      TERMINAL *t;
  887.      int row;
  888.      int col;
  889. {
  890.   DV_BOOL disp;                    /* cursor displayed? */
  891.  
  892.   if ((t->curpos.row != row || t->curpos.col != col) &&
  893.       row >= 0 && col >= 0)
  894.     {
  895.       disp = PresentCursor (t, (DV_BOOL) NO);
  896.       V_TPSET (&t->curpos, row, col);
  897.       PresentCursor (t, disp);
  898.     }
  899. }
  900.  
  901. /* Routines to increment or decrement a TA_POSITION,
  902. |  and to get the midpoint of two TA_POSITIONs
  903. */
  904.  
  905. /* TaPosInc() -- Increment a TA_POSITION. */
  906. LOCAL void 
  907. TaPosInc (ta, p)
  908.      TEXTARRAY ta;
  909.      TA_POSITION *p;
  910. {
  911.   int lastcol, lastrow;
  912.  
  913.   lastcol = VUtaGetWidth (ta) - 1;
  914.   lastrow = VUtaGetHeight (ta) - 1;
  915.  
  916.   if (p->col >= lastcol)        /* last column */
  917.     {                           /* move to next row */
  918.       if (p->row < lastrow)
  919.         {
  920.           p->row++;
  921.           p->col = 0;
  922.         }
  923.       else
  924.         {                       /* position at last row/col */
  925.           p->row = lastrow;
  926.           p->col = lastcol;
  927.         }
  928.     }
  929.   else                          /* next column */
  930.     p->col++;
  931. }
  932.  
  933. /* TaPosDec() -- Decrement a TA_POSITION. */
  934. LOCAL void 
  935. TaPosDec (ta, p)
  936.      TEXTARRAY ta;
  937.      TA_POSITION *p;
  938. {
  939.   if (p->col <= 0)              /* first column */
  940.     if (p->row > 0)
  941.       {                         /* move to previous row */
  942.         p->row--;
  943.         p->col = VUtaGetWidth (ta) - 1;
  944.       }
  945.     else                        /* position at first row/col */
  946.       p->row = p->col = 0;
  947.   else                          /* previous column */
  948.     p->col--;
  949. }
  950.  
  951. /* TaPosMidpt() -- Calculate the midpoint of two TA_POSITIONs. */
  952. LOCAL void 
  953. TaPosMidpt (ta, p1, p2, mid)
  954.      TEXTARRAY ta;
  955.      TA_POSITION *p1;
  956.      TA_POSITION *p2;
  957.      TA_POSITION *mid;
  958. {
  959.   int lowndx, hindx, midndx, width;
  960.  
  961.   TaPosSort (&p1, &p2);
  962.  
  963.   width = VUtaGetWidth (ta);
  964.   lowndx = p1->row * width + p1->col;
  965.   hindx = p2->row * width + p2->col;
  966.  
  967.   midndx = (lowndx + hindx) / 2;
  968.   mid->row = midndx / width;
  969.   mid->col = midndx % width;
  970. }
  971.  
  972. /* Reverse()
  973. |
  974. |  Reverse the foreground/background colors in the specified
  975. |  region for the specified textarray.  (Turns normal video
  976. |  into reverse video, and vice versa.)
  977. */
  978. LOCAL DV_BOOL 
  979. Reverse (ta, p1, p2)
  980.      TEXTARRAY ta;
  981.      TA_POSITION *p1;
  982.      TA_POSITION *p2;
  983. {
  984.   DV_BOOL rc = DV_SUCCESS;      /* return code */
  985.   TA_POSITION tp;               /* general purpose character position */
  986.   int height, width;
  987.   int row, start_col, end_col;
  988.  
  989.  
  990. /* Get height and width of text array */
  991.   width = VUtaGetWidth (ta);
  992.   height = VUtaGetHeight (ta);
  993.  
  994. /* Insure p1 is before p2 */
  995.   TaPosSort (&p1, &p2);
  996.  
  997. /* Do the reversing */
  998.   for (row = p1->row; row <= p2->row && row < height; row++)
  999.     {
  1000.       int ncols;
  1001.  
  1002.       if (row <= p1->row)
  1003.         {
  1004.           start_col = p1->col;
  1005.           if (row >= p2->row)
  1006.             end_col = p2->col;
  1007.           else
  1008.             end_col = width - 1;
  1009.         }
  1010.       else if (row >= p2->row)
  1011.         {
  1012.           start_col = 0;
  1013.           end_col = p2->col;
  1014.         }
  1015.       else
  1016.         {
  1017.           start_col = 0;
  1018.           end_col = width - 1;
  1019.         }
  1020.       ncols = end_col - start_col + 1;
  1021.       rc &= VUtaSwapColor (ta, V_TPSET (&tp, row, start_col), ncols);
  1022.     }
  1023.   return rc;
  1024. }
  1025.  
  1026. /* TaPosCmp()
  1027. |
  1028. |  Return
  1029. |    neg number if p1 <  p2
  1030. |     0     if p1 == p2
  1031. |    pos number if p1 >  p2
  1032. */
  1033. LOCAL int 
  1034. TaPosCmp (p1, p2)
  1035.      TA_POSITION *p1;
  1036.      TA_POSITION *p2;
  1037. {
  1038.   if (p1->row > p2->row)
  1039.     return 1;
  1040.   else if (p1->row < p2->row)
  1041.     return -1;
  1042.   else if (p1->col > p2->col)
  1043.     return 1;
  1044.   else if (p1->col < p2->col)
  1045.     return -1;
  1046.   else
  1047.     return 0;
  1048. }
  1049.  
  1050. /* TaPosSort()
  1051. |
  1052. |  Place p1 and p2 in ascending order.
  1053. */
  1054. LOCAL void 
  1055. TaPosSort (p1, p2)
  1056.      TA_POSITION **p1;
  1057.      TA_POSITION **p2;
  1058. {
  1059.   if (TaPosCmp (*p1, *p2) > 0)
  1060.     {
  1061.       TA_POSITION *tmp = *p1;
  1062.       *p1 = *p2;
  1063.       *p2 = tmp;
  1064.     }
  1065. }
  1066.  
  1067. /* Repl()
  1068. |
  1069. |  Replace all occurences of one character with another in a string.
  1070. */
  1071. LOCAL char *
  1072. Repl (buf, from, to)
  1073.      char *buf;
  1074.      int from;
  1075.      int to;
  1076. {
  1077.   char *s = buf;
  1078.  
  1079.   if (s)
  1080.     while (*s)
  1081.       {
  1082.         if (*s == from)
  1083.           *s = to;
  1084.         s++;
  1085.       }
  1086.   return buf;
  1087. }
  1088.  
  1089. /* Boxta()
  1090. |  Draw rectangles around the text arrays
  1091. */
  1092. LOCAL void 
  1093. Boxta (ta, color)
  1094.      TEXTARRAY ta;
  1095.      int color;
  1096. {
  1097.   RECTANGLE svp;
  1098.  
  1099.   VUtaBox (ta, &svp);
  1100.   RectExpand (&svp, 1);
  1101.   GRcolor (color);
  1102.   GRrectangle (&svp.ll, &svp.ur);
  1103. }
  1104.  
  1105. /* PickRegion()
  1106. |
  1107. |  Display region and get two picks from user
  1108. |  to defind rectangular region on screen.
  1109. */
  1110. LOCAL void
  1111. PickRegion (msg, region)
  1112.      char *msg;
  1113.      RECTANGLE *region;
  1114. {
  1115. #define    WHITE    15      /* white (on color display) */
  1116. #define    BLACK    0       /* black (on color display) */
  1117.  
  1118.   LOCAL DV_POINT ll =
  1119.   {1, 1};                       /* close to ll corner of screen */
  1120.   OBJECT loc;
  1121.  
  1122.  
  1123. /* display message in lower-lefthand corner of screen */
  1124.   GRcolor (WHITE);
  1125.   GRbackcolor (BLACK);
  1126.   GRch_size (DEF_TEXT_SIZE + 2, DEF_TEXT_SIZE + 2);
  1127.   GRmove (&ll);
  1128.   GRtext (msg);
  1129.  
  1130. /* Get first point from user */
  1131.   do
  1132.     {
  1133.       loc = TloPoll (WAIT_PICK);
  1134.     }
  1135.   while (0 == VOloKey (loc));
  1136.   cpybuf ((char *) & region->ll,
  1137.           (char *) VOloScpGet (loc), sizeof (region->ll));
  1138.   Cross (®ion->ll, WHITE);
  1139.  
  1140. /* Get second point from user */
  1141.   do
  1142.     {
  1143.       loc = TloPoll (WAIT_PICK);
  1144.       cpybuf ((char *) & region->ur,
  1145.               (char *) VOloScpGet (loc), sizeof (region->ur));
  1146.     }
  1147.   while (0 == VOloKey (loc));
  1148.   Cross (®ion->ll, BLACK);
  1149.   cpybuf ((char *) & region->ur,
  1150.           (char *) VOloScpGet (loc), sizeof (region->ur));
  1151.  
  1152. /* Draw box and return */
  1153.   VOuVpSort (region);
  1154.   DrawBox (region, WHITE);
  1155. }
  1156.  
  1157. /* Cross()
  1158. |
  1159. |  Draw cross centered at location given,
  1160. |  in given color.
  1161. */
  1162. LOCAL void 
  1163. Cross (pt, color)
  1164.      DV_POINT *pt;
  1165.      int color;
  1166. {
  1167. #define    CROSS_SIZE    4
  1168.   DV_POINT p1, p2;
  1169.  
  1170. /* horiz */
  1171.   p1.x = pt->x - CROSS_SIZE;
  1172.   p2.x = pt->x + CROSS_SIZE;
  1173.   p1.y = p2.y = pt->y;
  1174.   GRcolor (color);
  1175.   GRmove_and_vector (&p1, &p2);
  1176.  
  1177. /* vert */
  1178.   p1.x = p2.x = pt->x;
  1179.   p1.y = pt->y - CROSS_SIZE;
  1180.   p2.y = pt->y + CROSS_SIZE;
  1181.   GRmove_and_vector (&p1, &p2);
  1182.  
  1183. /* flush graphics output */
  1184.   GRflush ();
  1185. }
  1186.  
  1187. /* GetScrBox()
  1188. |
  1189. | Get bounding box (in screen coordinates)
  1190. | of the given object.
  1191. */
  1192. LOCAL void 
  1193. GetScrBox (obj, svp)
  1194.      OBJECT obj;
  1195.      RECTANGLE *svp;
  1196. {
  1197.   RECTANGLE
  1198.     wvp,                        /* bounding box in world coordinates */
  1199.     vvp,                        /* bounding box in virtual coordinates */
  1200.     svp_delta;                  /* screen coord delta from wvp */
  1201.  
  1202. /* Make sure parameters are valid */
  1203.   if (!obj || !VOobValid (obj) || !svp)
  1204.     return;
  1205.  
  1206. /* Get Bounding box in world coordinates */
  1207.   VOobBox (obj, &wvp, &svp_delta);
  1208.  
  1209. /* Do a wierd conversion to virtual coordinates.
  1210. |  This works ONLY BECAUSE we are using the full screen.
  1211. */
  1212.   vvp.ll.x = wvp.ll.x + XMAX;
  1213.   vvp.ll.y = wvp.ll.y + YMAX;
  1214.   vvp.ur.x = wvp.ur.x + XMAX;
  1215.   vvp.ur.y = wvp.ur.y + YMAX;
  1216.  
  1217. /* Convert to screen coordinates */
  1218.   GRvcs_to_scs (&vvp.ll, &svp->ll);
  1219.   GRvcs_to_scs (&vvp.ur, &svp->ur);
  1220.  
  1221. /* Adjust by screen coord delta */
  1222.   VOuVpSort (svp);
  1223.   VOuVpSort (&svp_delta);
  1224.   svp->ll.x -= svp_delta.ll.x;
  1225.   svp->ll.y -= svp_delta.ll.y;
  1226.   svp->ur.x += svp_delta.ur.x;
  1227.   svp->ur.y += svp_delta.ur.y;
  1228.  
  1229. /* Force bounding box to be within the bounds of the screen */
  1230.   while (svp->ll.x < sfull_screen.ll.x)
  1231.     {
  1232.       svp->ll.x++;
  1233.       svp->ur.x++;
  1234.     }
  1235.   while (svp->ll.y < sfull_screen.ll.y)
  1236.     {
  1237.       svp->ll.y++;
  1238.       svp->ur.y++;
  1239.     }
  1240.   while (svp->ur.x > sfull_screen.ur.x)
  1241.     svp->ur.x--;
  1242.   while (svp->ur.y > sfull_screen.ur.y)
  1243.     svp->ur.y--;
  1244. }
  1245.  
  1246. /* DrawBox()
  1247. |
  1248. |  Draw box specified by rectangle in given color.
  1249. */
  1250. LOCAL void
  1251. DrawBox (r, color)
  1252.      RECTANGLE *r;
  1253.      int color;
  1254. {
  1255.   GRcolor (color);
  1256.   GRrectangle (&r->ll, &r->ur);
  1257.   GRflush ();
  1258. }
  1259.  
  1260. /* RectExpand()
  1261. |
  1262. |  Expand a rectangle by the given number of pixels on each side.
  1263. */
  1264. LOCAL void 
  1265. RectExpand (r, p)
  1266.      RECTANGLE *r;
  1267.      DV_COORD p;
  1268. {
  1269.   r->ll.x -= p;
  1270.   r->ll.y -= p;
  1271.   r->ur.x += p;
  1272.   r->ur.y += p;
  1273. }
  1274.  
  1275. /* cpybuf()
  1276. |
  1277. |  Copy the contents of one portion of memory
  1278. |  to another, one character at a time.
  1279. */
  1280. LOCAL void 
  1281. cpybuf (to, from, numchars)
  1282.      char *to;
  1283.      char *from;
  1284.      int numchars;
  1285. {
  1286.   for (; numchars > 0; numchars--)
  1287.     *to++ = *from++;
  1288. }
  1289.  
  1290. /* Usage()
  1291. |
  1292. |  Print usage of program and exit.
  1293. */
  1294. LOCAL void 
  1295. Usage (ProgName)
  1296.      char *ProgName;
  1297. {
  1298.   fprintf (stderr, "Usage: %s [ %s [ %s [ %s ] ] ]\n",
  1299.                   ProgName,
  1300.                   "display_device",
  1301.                   "layout_file",
  1302.                   "search_path");
  1303.   exit (EXIT_ERR);
  1304. }
  1305.